package com.ropzsu.scalaWeb

import java.net._
import scala.actors.Actor
import scala.actors.Actor._
import org.apache.log4j.Logger;
import com.ropzsu.scalaWeb.util.HttpRequest;
import com.ropzsu.scalaWeb.util.MimeMap;
import java.io.File

object httpd {
  val logger = Logger.getLogger("scala.actor");

  def flow(name: String, length: long, is: java.io.InputStream , os: java.io.OutputStream): unit =   {

    var buf = new Array[byte](8 * 1024)
    var numRead: Int = is.read(buf)
    while ( numRead  >= 0) {
      os.write(buf, 0, numRead)
      numRead = is.read(buf)
    }
    
  }


  def servier(id: Int ): Actor = actor {
    var count = 0;
    var buffer = new Array[byte](8192)
    var request = new HttpRequest()
    var mimemap = new MimeMap()
    var htdocs = java.lang.System.getProperty("scala.htdocs")
    val df = new java.text.SimpleDateFormat("yyyy-MMM-dd HH:mm:ss", new java.util.Locale("en_US"))

    loop {
      react {
        case sock: Socket =>
          val in  = sock.getInputStream()
        val out = sock.getOutputStream()

        try {

	  var hpart = request.headerPart(in)
	  
	  var loc = java.net.URLDecoder.decode(request.doGetPATH(hpart), "UTF-8")
	  loc = loc.replace("..", "")
	  
	  var ct = mimemap.getContentTypeFor(loc)
	  if (ct == null) ct = "text/plain"
	  var file = new java.io.File(htdocs + loc)

	  var code = "200 OK"
	  var executionStart: long  = 0;
	  var total : long = 0;
	  if (file.exists() && file.isFile()) {
	    executionStart = scala.compat.Platform.currentTime 
	    var http_head = request.headerResponse(code, file.length(), ct)
            out.write( http_head.getBytes(), 0, http_head.length )
	    out.write("\r\n".getBytes(), 0, "\r\n".length)
	    out.flush()
	    flow(loc, file.length(), new java.io.FileInputStream(file), out)
	    total = scala.compat.Platform.currentTime - executionStart
	  } 
	  else if (file.exists() && file.isDirectory() ) {
	    var dir_rs = new java.lang.StringBuilder(8*1024)
	    var file_rs = new java.lang.StringBuilder(8*1024);
	    var fileNames = file.listFiles().map( x => x.getName()) 
	    scala.util.Sorting.quickSort(fileNames)
	    for ( f <- fileNames) {
              val item = new File(htdocs + loc + f )
	      var modify = df.format(new java.util.Date(item.lastModified()))
	      var xct = mimemap.getContentTypeFor(item.getName())
	      if (xct == null) xct = "application/octet-stream"
	      if(item.isFile()) {
		val td = "<tr><td class=\"n\"><a href=\"" + loc + item.getName() + "\">" + item.getName() + "</a></td><td class=\"m\">" + modify + "</td><td class=\"s\">" + item.length() + "</td><td class=\"t\">" + xct + "</td></tr>" + "\n"
		file_rs.append(td)
	      } 
	      if(item.isDirectory()) {
		val td = "<tr><td class=\"n\"><a href=\"" + loc + item.getName()  + "/\">" + item.getName() + "/</a></td><td class=\"m\">" + modify + "</td><td class=\"s\">-</td><td class=\"t\">Directory</td></tr>" + "\n"
		dir_rs.append(td)
	      } 
	    }
	    var content = request.dirList( loc, dir_rs.toString() + file_rs.toString())
	    var http_head = request.headerResponse("200 OK", content.getBytes().length, "text/html")
	    out.write(http_head.getBytes(), 0, http_head.length)
	    out.write("\r\n".getBytes(), 0, "\r\n".length)
	    out.write(content.getBytes(), 0, content.getBytes().length)
	  }
	      else {
		code = "404 Not Found"
		var page404 = "HTTP/1.0 404 Not Found\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n<h3>ERROR 404: Not Found</h3>" + loc
		out.write(page404.getBytes(), 0, page404.length())
	      }

          in.close()
          out.close()
          sock.close() 

          logger.info("Actor: " + id + ".  GET " + loc + " [" + code + "] times: [" + total + "] ms")
        } catch   {
          case ex: Exception =>
          logger.warn(ex.getMessage())
          in.close()
          out.close()
          sock.close()
        }
        case 'exit => exit()
      }
    }
  }

  def main(args: Array[String]): unit = {
    var n   = 0 
    var port: String = java.lang.System.getProperty("scala.port")
    if (port ==  null) port = "8000"
    var host = java.lang.System.getProperty("scala.host")
    if (host == null) host = "localhost"

    val addr =  InetAddress.getByName(host)
    val max = 5000   
    val socksvr = new ServerSocket(java.lang.Integer.parseInt(port), max, addr)

    val ks = new Array[Actor](max);
    System.out.println("Starting " + max + " actors")
    for (val x <- 0 until max) ks(x) = servier(x)

    while (true) {
      val s = socksvr.accept()
      n = n + 1
      if (n < 0) n = 0 // over-flow int
      ks( n%max ) ! s
    }
  }  
}

